// festarter.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "festarter.h"
#include "util.h"
#include "fecoremain.h"

#define MAX_LOADSTRING 100
#define FECOREDLL_NAME "fecore_wince.dll"
#define FEMAINPROC_NAME "FeCoreMain"
#define WM_LOADCOMPLETE (WM_USER + 0)

typedef struct {
	HBITMAP bmSplash; // Splash screen
} WNDDATA, *PWNDDATA;

typedef struct {
	HWND hWnd;
	FECOREMAINPROC lpFeCoreMainProc;
} THREADPARAM, *PTHREADPARAM;

typedef struct {
	HWND hWnd;
} CALLBACKPARAM, *PCALLBACKPARAM;

// Global Variables:
HINSTANCE g_hInst; // current instance

// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE, LPTSTR);
BOOL InitInstance(HINSTANCE, PTHREADPARAM);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
VOID WndOnCreate(HWND hWnd);
VOID WndOnDestroy(HWND hWnd);
VOID WndOnPaint(HWND);
HINSTANCE LoadFeCoreDll(VOID);
DWORD WINAPI LoaderThreadProc(LPVOID);
VOID StarterCallbackProc(LPVOID lpParam);

int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPTSTR    lpCmdLine,
                   int       nCmdShow)
{
	MSG msg;
	THREADPARAM param;
	HANDLE hStarterThread;

	// Perform application initialization:
	if (!InitInstance(hInstance, &param)) 
	{
		return FALSE;
	}

	hStarterThread = CreateThread(
		NULL, // lpThreadAttributes
		0, // dwStackSize
		LoaderThreadProc, // lpStartAddres
		&param, // lpParameter
		CREATE_SUSPENDED, // dwCreationFlags
		NULL // lpThreadId
		);

	ResumeThread(hStarterThread);

	// Main message loop:
	while (GetMessage(&msg, NULL, 0, 0)) 
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);	
	}

	WaitForSingleObject(hStarterThread, INFINITE);
	CloseHandle(hStarterThread);
	
	if(!param.lpFeCoreMainProc)
	{
		return FALSE;
	}

	CALLBACKPARAM callback_param;
	callback_param.hWnd = param.hWnd;
	
	FESTARTER_CALLBACK callback;
	callback.lpfnHideSplash = StarterCallbackProc;
	callback.lpParam = &callback_param;

	// report status when started from HKLM\init
	if(_tcslen(lpCmdLine))
	{
		SignalStarted(_ttol(lpCmdLine));
	}
		 
	return param.lpFeCoreMainProc(
		hInstance, hPrevInstance, lpCmdLine, nCmdShow, &callback);
}

//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
ATOM MyRegisterClass(HINSTANCE hInstance, LPTSTR szWindowClass)
{
	WNDCLASS wc;

	wc.style         = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc   = WndProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = sizeof(LONG);
	wc.hInstance     = hInstance;
	wc.hIcon         = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_FESTARTER_WINCE));
	wc.hCursor       = 0;
	wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
	wc.lpszMenuName  = 0;
	wc.lpszClassName = szWindowClass;

	return RegisterClass(&wc);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, PTHREADPARAM pThreadParam)
{
    HWND hWnd;
    TCHAR szTitle[MAX_LOADSTRING];		// title bar text
    TCHAR szWindowClass[MAX_LOADSTRING];	// main window class name

    g_hInst = hInstance; // Store instance handle in our global variable

    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); 
    LoadString(hInstance, IDC_FESTARTER_WINCE, szWindowClass, MAX_LOADSTRING);

    if (!MyRegisterClass(hInstance, szWindowClass))
    {
    	return FALSE;
    }

    hWnd = CreateWindow(szWindowClass, szTitle, WS_POPUP,
        0, 0, 0, 0, NULL, NULL, hInstance, NULL);

    if (!hWnd)
    {
        return FALSE;
    }

	PWNDDATA pWndData = (PWNDDATA)GetWindowLong(hWnd, 0);

	pThreadParam->hWnd = hWnd;
	ShowSplashWindow(hWnd);
    UpdateWindow(hWnd);

    //if (g_hWndCommandBar)
    //{
    //    CommandBar_Show(g_hWndCommandBar, TRUE);
    //}

    return TRUE;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_COMMAND	- process the application menu
//  WM_PAINT	- Paint the main window
//  WM_DESTROY	- post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    
    switch (message) 
    {
        case WM_CREATE:
			WndOnCreate(hWnd);
            break;

		case WM_PAINT:
			WndOnPaint(hWnd); 
            break;
    
		case WM_DESTROY:
			WndOnDestroy(hWnd);
            break;

		case WM_LOADCOMPLETE:
			PostQuitMessage(0);
			break;

        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

VOID WndOnCreate(HWND hWnd) {
	PWNDDATA pWndData;
	pWndData = new WNDDATA;
	// load splash bitmap
	{
		HDC hdc;
		hdc = GetWindowDC(hWnd);
		int bpp = GetDeviceCaps(hdc,BITSPIXEL);
		
		switch(bpp)
		{
		case 16:
		case 24:
		case 32:
			pWndData->bmSplash = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_SPLASH_24BPP));
			break;

		default:
			pWndData->bmSplash = 0;
			break;
		}
		ReleaseDC(hWnd, hdc);
	}

	SetWindowLong(hWnd, 0, (LONG)pWndData);
}

VOID WndOnDestroy(HWND hWnd) {
	PWNDDATA pWndData = (PWNDDATA)GetWindowLong(hWnd, 0);
	if(pWndData->bmSplash)
	{
		DeleteObject(pWndData->bmSplash);
	}
	delete pWndData;
}

VOID WndOnPaint(HWND hWnd) {
	PWNDDATA pWndData = (PWNDDATA)GetWindowLong(hWnd, 0);
	HDC hdc;
	hdc = GetWindowDC(hWnd);
	
	if(pWndData->bmSplash)
	{
		HDC mem_hdc;
		mem_hdc = CreateCompatibleDC(hdc);
		{
			HGDIOBJ bm_old;
			bm_old = SelectObject(mem_hdc, pWndData->bmSplash);
			BitBlt(hdc, 0,0, 400, 234, mem_hdc, 0, 0, SRCCOPY);
			SelectObject(mem_hdc, bm_old);
		}
		DeleteDC(mem_hdc);
	}
	ReleaseDC(hWnd, hdc);
}

HINSTANCE LoadFeCoreDll(VOID) {
	TCHAR szFeCoreDllPath[MAX_PATH + 1];
	if(!GetFeCoreDllPath(szFeCoreDllPath, MAX_PATH + 1))
	{
		return 0;
	}

	_tcscat_s(szFeCoreDllPath, MAX_PATH + 1, _T(FECOREDLL_NAME));

	return LoadLibrary(szFeCoreDllPath);
}

DWORD WINAPI LoaderThreadProc(LPVOID lpParameter) {
	PTHREADPARAM pThreadParam = (PTHREADPARAM)lpParameter;

	do
	{
		HINSTANCE hFeCore = LoadFeCoreDll();
		if(!hFeCore)
		{
			break;
		}
		
		pThreadParam->lpFeCoreMainProc = (FECOREMAINPROC)GetProcAddress(hFeCore, _T(FEMAINPROC_NAME));

		if(!pThreadParam->lpFeCoreMainProc)
		{
			FreeLibrary(hFeCore);
			break;
		}

	} while(0);

	PostMessage(
		pThreadParam->hWnd, // hWnd
		WM_LOADCOMPLETE, // Msg
		NULL, // wParam
		0L // lParam
		);
	
	return pThreadParam->lpFeCoreMainProc ? 0 : 1;
}

VOID StarterCallbackProc(LPVOID lpParam) {
	PCALLBACKPARAM param = (PCALLBACKPARAM)lpParam;

	if(param->hWnd)
	{
		DestroyWindow(param->hWnd);
		param->hWnd = 0;
	}
}